﻿using System;
using System.Threading.Tasks;
using Ndns.ServerHost.Abstractions.Services;

namespace Ndns.ServerHost.Abstractions
{
    public interface IMiddlewaresBuilder
    {
        IMiddlewaresBuilder Use(IMiddleware middleware);
    }

    public static class MiddlewaresBuilderExtensions
    {
        public static IMiddlewaresBuilder Use(this IMiddlewaresBuilder builder, Func<DnsContext, RequestDelegate, Task> action)
        {
            builder.Use(new MiddlewareWrapperOfFunc2(action));
            return builder;
        }

        public static IMiddlewaresBuilder Run(this IMiddlewaresBuilder builder, Action<DnsContext> action)
        {
            builder.Use(new MiddlewareWrapperOfAction(action));
            return builder;
        }

        public static IMiddlewaresBuilder Run(this IMiddlewaresBuilder builder, RequestDelegate action)
        {
            builder.Use(new MiddlewareWrapperOfFunc1(action));
            return builder;
        }
    }

    abstract class MiddlewareWrapper : IMiddleware
    {
        protected RequestDelegate _next;
        public abstract Task InvokeAsync(DnsContext context);
        public void RegisterServices(IServiceCollection services, RequestDelegate next)
        {
            _next = next;
        }
        public void Start() { }
        public void Dispose() { }
    }

    class MiddlewareWrapperOfAction : MiddlewareWrapper
    {
        private readonly Action<DnsContext> _action;
        public MiddlewareWrapperOfAction(Action<DnsContext> action) { _action = action; }
        public override Task InvokeAsync(DnsContext context)
        {
            _action.Invoke(context);
            return Task.CompletedTask;
        }
    }

    class MiddlewareWrapperOfFunc1 : MiddlewareWrapper
    {
        private readonly RequestDelegate _action;
        public MiddlewareWrapperOfFunc1(RequestDelegate action) { _action = action; }
        public override Task InvokeAsync(DnsContext context)
        {
            return _action.Invoke(context);
        }
    }

    class MiddlewareWrapperOfFunc2 : MiddlewareWrapper
    {
        private readonly Func<DnsContext, RequestDelegate, Task> _action;
        public MiddlewareWrapperOfFunc2(Func<DnsContext, RequestDelegate, Task> action) { _action = action; }
        public override Task InvokeAsync(DnsContext context)
        {
            return _action.Invoke(context, _next);
        }
    }
}
